#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007  Donald N. Allingham
# Copyright (C) 2012       Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gi.repository import Gdk
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import GObject

import cairo
import sys, os
import platform

try:
    import bsddb3 as bsddb # ok, in try/except
    BSDDB_STR = str(bsddb.__version__) + " " + str(bsddb.db.version())
except:
    BSDDB_STR = 'not found'

try:
    import sqlite3
    sqlite3_py_version_str = sqlite3.version
    sqlite3_version_str = sqlite3.sqlite_version
except:
    sqlite3_version_str = 'not found'
    sqlite3_py_version_str = 'not found'

#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.const import ICON, SPLASH, URL_BUGTRACKER
from gramps.gen.constfunc import get_env_var
from gramps.version import VERSION
from ..display import display_help, display_url
from ..managedwindow import ManagedWindow

#-------------------------------------------------------------------------
#
# ErrorReportAssistant
#
#-------------------------------------------------------------------------
class ErrorReportAssistant(ManagedWindow, Gtk.Assistant):
    """
    Give the user an opportunity to report an error on the Gramps bug
    reporting system.
    """
    def __init__(self, error_detail, rotate_handler,
                 ownthread=False, parent=None):
        Gtk.Assistant.__init__(self)
        ManagedWindow.__init__(self, None, [], self.__class__, modal=True)
        if parent is not None: # the next two will not be set in ManagedWindow
            self.parent_window = parent
            self.other_modal_window = parent
        self.set_window(self, None, None, isWindow=True)
        if self.parent_window is not None:
            self.setup_configs('interface.errorreportassistant', 780, 520)

        try:
            # did we get a handler wrapping the error detail?
            self._error_detail = error_detail.get_formatted_log()
        except AttributeError:
            self._error_detail = error_detail

        self._rotate_handler = rotate_handler

        self._sys_information_text_buffer = None
        self._user_information_text_buffer = None
        self._error_details_text_buffer = None
        self._final_report_text_buffer = None

        self.set_title(_("Error Report Assistant"))
        self.connect('close', self.do_close)
        self.connect('cancel', self.do_close)
        self.connect('prepare', self.prepare)

        #create the assistant pages
        self.create_page_intro()
        self.build_page1()
        self.build_page2()
        self.build_page3()
        self.build_page4()
        self.build_page5()
        self.create_page_summary()

        self.show() # ManagedWindow

        self.ownthread = ownthread
        if self.ownthread:
            Gtk.main()

    def do_close(self, *obj):
        """
        Close the assistant.
        """
        if self.parent_window is not None:
            self._save_position(save_config=False) # the next line saves it
            self._save_size()
        self.destroy()
        if self.ownthread:
            Gtk.main_quit()

    def prepare(self, assistant, page):
        """
        Prepare pages prior to display.
        """
        self.page4_update()
        self.set_page_complete(page, True)

    def _copy_to_clipboard(self, obj=None):
        """
        Copy the bug report to the clipboard.
        """
        clipboard = Gtk.Clipboard.get_for_display(Gdk.Display.get_default(),
                    Gdk.SELECTION_CLIPBOARD)
        clipboard.set_text(
            self._final_report_text_buffer.get_text(
              self._final_report_text_buffer.get_start_iter(),
              self._final_report_text_buffer.get_end_iter(), True), -1)

        clipboard = t = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY)
        clipboard.set_text(
            self._final_report_text_buffer.get_text(
              self._final_report_text_buffer.get_start_iter(),
              self._final_report_text_buffer.get_end_iter(), True), -1)

    def _start_email_client(self, obj=None):
        """
        Start an email client to send the report.
        """
        display_url('mailto:gramps-bugs@lists.sourceforge.net?subject='
                          '"bug report"&body="%s"' \
                          % self._final_report_text_buffer.get_text(
                        self._final_report_text_buffer.get_start_iter(),
                        self._final_report_text_buffer.get_end_iter(), True))

    def _start_gramps_bts_in_browser(self, obj=None):
        """
        Start a web browser to report the bug.
        """
        display_url(URL_BUGTRACKER)

    def _get_sys_information(self):
        """
        Get relevant system information.
        """
        distribution = "" # print nothing if there's nothing to print
        if hasattr(os, "uname"):
            distribution = "Distribution: %s\n" % os.uname()[2]

        sqlite = ''
        if __debug__:
            sqlite = "sqlite version: %s (%s) \n" % (sqlite3_version_str,
                                                     sqlite3_py_version_str)

        return "Gramps version: %s \n"\
               "Python version: %s \n"\
               "BSDDB version: %s \n"\
               "%s"\
               "LANG: %s\n"\
               "OS: %s\n"\
               "%s\n"\
               "GTK version    : %s\n"\
               "gobject version: %s\n"\
               "cairo version  : %s"\
               % (str(VERSION),
                  str(sys.version).replace('\n',''),
                  BSDDB_STR,
                  sqlite,
                  get_env_var('LANG',''),
                  platform.system(),
                  distribution,
                  '%d.%d.%d' % (Gtk.get_major_version(),
                                Gtk.get_minor_version(),
                                Gtk.get_micro_version()),
                  '%d.%d.%d' % GObject.pygobject_version,
                  cairo.version_info)

    def _reset_error_details(self, obj=None):
        """
        Reset the error details buffer to its original contents.
        """
        self._error_details_text_buffer.set_text(
            "\n".join(self._rotate_handler.get_formatted_log(
                        self._error_detail)))

    def _clear_error_details(self, obj=None):
        """
        Clear the error details buffer.
        """
        self._error_details_text_buffer.delete(
            self._error_details_text_buffer.get_start_iter(),
            self._error_details_text_buffer.get_end_iter())

    def _reset_sys_information(self, obj=None):
        """
        Reset the system information buffer to its original contents.
        """
        self._sys_information_text_buffer.set_text(
            self._get_sys_information())

    def _clear_sys_information(self, obj=None):
        """
        Clear the system information buffer.
        """
        self._sys_information_text_buffer.delete(
            self._sys_information_text_buffer.get_start_iter(),
            self._sys_information_text_buffer.get_end_iter())

    def _clear_user_information(self, obj=None):
        """
        Clear the user information buffer.
        """
        self._user_information_text_buffer.delete(
            self._user_information_text_buffer.get_start_iter(),
            self._user_information_text_buffer.get_end_iter())

    def create_page_intro(self):
        """
        Create the introduction page.
        """
        label = Gtk.Label(label=self.get_intro_text())
        label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(SPLASH)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(image, False, False, 5)
        box.pack_start(label, False, False, 5)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _('Report a bug'))
        self.set_page_type(page, Gtk.AssistantPageType.INTRO)

    def get_intro_text(self):
        """
        Return the text of the introduction page.
        """
        return _("This is the Bug Reporting Assistant. It will "
              "help you to make a bug report to the Gramps "
              "developers that will be as detailed as possible.\n\n"
              "The assistant will ask you a few questions and will "
              "gather some information about the error that has "
              "occurred and the operating environment. "
              "At the end of the assistant you will be asked to "
              "file a bug report on the Gramps bug tracking system. "
              "The assistant will place the bug report on the clip board so "
              "that you can paste it into the form on the bug tracking "
              "website and review exactly what information you want to "
              "include.")

    def build_page1(self):
        """
        Build the error details page.
        """
        label = Gtk.Label(label=_("If you can see that there is any personal "
                            "information included in the error please remove "
                            "it."))
        label.set_halign(Gtk.Align.START)
        label.set_padding(0, 4)
        label.set_line_wrap(True)

        swin = Gtk.ScrolledWindow()
        swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)

        textview = Gtk.TextView()

        self._error_details_text_buffer = textview.get_buffer()
        self._reset_error_details()

        swin.add(textview)

        sw_frame = Gtk.Frame()
        sw_frame.add(swin)

        reset = Gtk.Button("Reset")
        reset.connect('clicked', self._reset_error_details)
        clear = Gtk.Button("Clear")
        clear.connect('clicked', self._clear_error_details)

        button_box = Gtk.ButtonBox()
        button_box.set_border_width(6)
        button_box.set_spacing(6)
        button_box.set_layout(Gtk.ButtonBoxStyle.END)

        button_box.pack_end(reset, False, False, 0)
        button_box.pack_end(clear, False, False, 0)

        error_details_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        error_details_box.pack_start(label, False, False, 0)
        error_details_box.pack_start(sw_frame, True, True, 0)
        error_details_box.pack_start(button_box, False, False, 0)
        error_details_box.set_hexpand(True)
        error_details_box.set_vexpand(True)

        error_details_box.set_property("margin", 12)

        error_details_frame = Gtk.Frame()
        error_details_frame.set_border_width(3)
        error_details_frame.set_label("<b>%s</b>" % _("Error Details"))
        error_details_frame.get_label_widget().set_use_markup(True)

        error_details_frame.add(error_details_box)

        side_label = Gtk.Label(label=_("This is the detailed Gramps error "
                                 "information, don't worry if you do not "
                                 "understand it. You will have the opportunity "
                                 "to add further detail about the error "
                                 "in the following pages of the assistant."))

        side_label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(ICON)

        heading = Gtk.Box()
        heading.pack_start(side_label, True, True, 5)
        heading.pack_start(image, False, False, 5)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(heading, False, False, 5)
        box.pack_start(error_details_frame, True, True, 0)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _("Error Details"))
        self.set_page_type(page, Gtk.AssistantPageType.CONTENT)

    def build_page2(self):
        """
        Build the system information page.
        """
        label = Gtk.Label(label=_("Please check the information below and "
                            "correct anything that you know to be wrong or "
                            "remove anything that you would rather not have "
                            "included in the bug report."))
        label.set_halign(Gtk.Align.START)
        label.set_padding(0, 4)
        label.set_line_wrap(True)

        swin = Gtk.ScrolledWindow()
        swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)

        textview = Gtk.TextView()

        self._sys_information_text_buffer = textview.get_buffer()
        self._reset_sys_information()

        swin.add(textview)

        sw_frame = Gtk.Frame()
        sw_frame.add(swin)

        reset = Gtk.Button("Reset")
        reset.connect('clicked', self._reset_sys_information)
        clear = Gtk.Button("Clear")
        clear.connect('clicked', self._clear_sys_information)


        button_box = Gtk.ButtonBox()
        button_box.set_border_width(6)
        button_box.set_spacing(6)
        button_box.set_layout(Gtk.ButtonBoxStyle.END)

        button_box.pack_end(reset, False, False, 0)
        button_box.pack_end(clear, False, False, 0)

        sys_information_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        sys_information_box.pack_start(label, False, False, 0)
        sys_information_box.pack_start(sw_frame, True, True, 0)
        sys_information_box.pack_start(button_box, False, False, 0)
        sys_information_box.set_hexpand(True)
        sys_information_box.set_vexpand(True)
        sys_information_box.set_property("margin", 12)

        sys_information_frame = Gtk.Frame()
        sys_information_frame.set_border_width(3)
        sys_information_frame.set_label("<b>%s</b>" % _("System Information"))
        sys_information_frame.get_label_widget().set_use_markup(True)

        sys_information_frame.add(sys_information_box)

        side_label = Gtk.Label(label=_("This is the information about your "
                                 "system that will help the developers to fix "
                                 "the bug."))

        side_label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(ICON)

        heading = Gtk.Box()
        heading.pack_start(side_label, True, True, 5)
        heading.pack_start(image, False, False, 5)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(heading, False, False, 5)
        box.pack_start(sys_information_frame, True, True, 0)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _("System Information"))
        self.set_page_type(page, Gtk.AssistantPageType.CONTENT)

    def build_page3(self):
        """
        Build the further information page.
        """
        label = Gtk.Label(label=_("Please provide as much information as you "
                             "can about what you were doing when the error "
                             "occurred."))
        label.set_halign(Gtk.Align.START)
        label.set_padding(0, 4)
        label.set_line_wrap(True)

        swin = Gtk.ScrolledWindow()
        swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)

        textview = Gtk.TextView()

        self._user_information_text_buffer = textview.get_buffer()

        swin.add(textview)

        sw_frame = Gtk.Frame()
        sw_frame.add(swin)

        clear = Gtk.Button("Clear")
        clear.connect('clicked', self._clear_user_information)

        button_box = Gtk.ButtonBox()
        button_box.set_border_width(6)
        button_box.set_spacing(6)
        button_box.set_layout(Gtk.ButtonBoxStyle.END)

        button_box.pack_end(clear, False, False, 0)

        user_information_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        user_information_box.pack_start(label, False, False, 0)
        user_information_box.pack_start(sw_frame, True, True, 0)
        user_information_box.pack_start(button_box, False, False, 0)
        user_information_box.set_hexpand(True)
        user_information_box.set_vexpand(True)
        user_information_box.set_property("margin", 12)

        user_information_frame = Gtk.Frame()
        user_information_frame.set_border_width(3)
        user_information_frame.set_label("<b>%s</b>" % _("Further Information"))
        user_information_frame.get_label_widget().set_use_markup(True)

        user_information_frame.add(user_information_box)

        side_label = Gtk.Label(label=_("This is your opportunity to describe "
                                 "what you were doing when the error occurred."))

        side_label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(ICON)

        heading = Gtk.Box()
        heading.pack_start(side_label, True, True, 5)
        heading.pack_start(image, False, False, 5)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(heading, False, False, 5)
        box.pack_start(user_information_frame, True, True, 0)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _("Further Information"))
        self.set_page_type(page, Gtk.AssistantPageType.CONTENT)

    def build_page4(self):
        """
        Build the bug report summary page.
        """
        label = Gtk.Label(label=_("Please check that the information is "
                            "correct, do not worry if you don't understand the "
                            "detail of the error information. Just make sure "
                            "that it does not contain anything that you do not "
                            "want to be sent to the developers."))
        label.set_halign(Gtk.Align.START)
        label.set_padding(0, 4)
        label.set_line_wrap(True)

        swin = Gtk.ScrolledWindow()
        swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)

        textview = Gtk.TextView()
        textview.set_editable(False)
        textview.set_cursor_visible(False)

        self._final_report_text_buffer = textview.get_buffer()

        swin.add(textview)

        sw_frame = Gtk.Frame()
        sw_frame.add(swin)

        summary_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        summary_box.pack_start(label, False, False, 0)
        summary_box.pack_start(sw_frame, True, True, 0)
        summary_box.set_hexpand(True)
        summary_box.set_vexpand(True)
        summary_box.set_property("margin", 12)

        summary_frame = Gtk.Frame()
        summary_frame.set_border_width(3)
        summary_frame.set_label("<b>%s</b>" % _("Bug Report Summary"))
        summary_frame.get_label_widget().set_use_markup(True)

        summary_frame.add(summary_box)

        side_label = Gtk.Label(label=_("This is the completed bug report. "
                                 "The next page of the assistant will help you "
                                 "to file a bug on the Gramps bug tracking "
                                 "system website."))

        side_label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(ICON)

        heading = Gtk.Box()
        heading.pack_start(side_label, True, True, 5)
        heading.pack_start(image, False, False, 5)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(heading, False, False, 5)
        box.pack_start(summary_frame, True, True, 0)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _("Bug Report Summary"))
        self.set_page_type(page, Gtk.AssistantPageType.CONTENT)

    def build_page5(self):
        """
        Build the send bug report page.
        """
        label = Gtk.Label(label=
            "%s <i>%s</i>" %
            (_("Use the two buttons below to first copy the bug report to the "
               "clipboard and then open a webbrowser to file a bug report at "),
               URL_BUGTRACKER))
        label.set_halign(Gtk.Align.START)
        label.set_padding(0, 4)
        label.set_line_wrap(True)
        label.set_use_markup(True)


        url_label = Gtk.Label(label=_("Use this button to start a web browser "
                                "and file a bug report on the Gramps bug "
                                "tracking system."))
        url_label.set_halign(Gtk.Align.START)
        url_label.set_padding(0, 4)
        url_label.set_line_wrap(True)
        url_label.set_size_request(200, -1)

        url_button = Gtk.Button("File bug report")
        url_button.connect('clicked', self._start_gramps_bts_in_browser)
        url_button_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        url_button_vbox.pack_start(url_button, True, False, 0)

        url_box = Gtk.Box()
        url_box.pack_start(url_label, True, True, 0)
        url_box.pack_start(url_button_vbox, False, False, 0)
        url_box.set_hexpand(True)
        url_box.set_property("margin", 12)

        url_frame = Gtk.Frame()
        url_frame.add(url_box)

        clip_label = Gtk.Label(label=_("Use this button "
                                 "to copy the bug report onto the clipboard. "
                                 "Then go to the bug tracking website by using "
                                 "the button below, paste the report and click "
                                 "submit report"))
        clip_label.set_halign(Gtk.Align.START)
        clip_label.set_padding(0, 4)
        clip_label.set_line_wrap(True)
        clip_label.set_size_request(200, -1)

        clip_button = Gtk.Button("Copy to clipboard")
        clip_button.connect('clicked', self._copy_to_clipboard)
        clip_button_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        clip_button_vbox.pack_start(clip_button, True, False, 0)

        clip_box = Gtk.Box()
        clip_box.pack_start(clip_label, True, True, 0)
        clip_box.pack_start(clip_button_vbox, False, False, 0)
        clip_box.set_hexpand(True)
        clip_box.set_property("margin", 12)

        clip_frame = Gtk.Frame()
        clip_frame.add(clip_box)

        inner_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        inner_box.pack_start(label, False, False, 0)
        inner_box.pack_start(clip_frame, False, False, 0)
        inner_box.pack_start(url_frame, False, False, 0)
        inner_box.set_property("margin", 12)

        outer_frame = Gtk.Frame()
        outer_frame.set_border_width(3)
        outer_frame.set_label("<b>%s</b>" % _("Send Bug Report"))
        outer_frame.get_label_widget().set_use_markup(True)

        outer_frame.add(inner_box)

        side_label = Gtk.Label(label=_("This is the final step. Use the "
                                 "buttons on this page to start a web browser "
                                 "and file a bug report on the Gramps bug "
                                 "tracking system."))

        side_label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(ICON)

        heading = Gtk.Box()
        heading.pack_start(side_label, True, True, 5)
        heading.pack_start(image, False, False, 5)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(heading, False, False, 5)
        box.pack_start(outer_frame, True, True, 0)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _("Send Bug Report"))
        self.set_page_type(page, Gtk.AssistantPageType.CONTENT)

    def create_page_summary(self):
        """
        Create the summary page.
        """
        text = _('Gramps is an Open Source project. Its success '
                 'depends on its users. User feedback is important. '
                 'Thank you for taking the time to submit a bug report.')
        label = Gtk.Label(label=text)
        label.set_line_wrap(True)

        image = Gtk.Image()
        image.set_from_file(SPLASH)

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.pack_start(image, False, False, 5)
        box.pack_start(label, False, False, 5)

        page = box

        page.show_all()
        self.append_page(page)
        self.set_page_title(page, _('Complete'))
        self.set_page_type(page, Gtk.AssistantPageType.SUMMARY)

    def page4_update(self):
        """
        Update the contents of page 4 with any changes made.
        """
        self._final_report_text_buffer.set_text(
            "User Information: \n" +
            "===================\n\n" +
            self._user_information_text_buffer.get_text(
              self._user_information_text_buffer.get_start_iter(),
              self._user_information_text_buffer.get_end_iter(), True) +

            "\n\n\nError Details: \n" +
            "===================\n\n" +

            self._error_details_text_buffer.get_text(
              self._error_details_text_buffer.get_start_iter(),
              self._error_details_text_buffer.get_end_iter(), True) +

            "\n\nSystem Information: \n" +
            "===================\n\n" +

            self._sys_information_text_buffer.get_text(
              self._sys_information_text_buffer.get_start_iter(),
              self._sys_information_text_buffer.get_end_iter(), True)
            )
